home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-12-20 | 55.2 KB | 1,551 lines | [TEXT/CWIE] |
- #include "ocheaders.h"
- #include "BDDISPIDs.h"
- #include "CBaseControl.h"
- #include "CErrorControl.h"
- #include "CLabelControl.h"
- #include "BDConsts.h"
- #include "Colors.h"
- #include "FnAssert.h"
- #include "dispatch.h"
- #include <LArray.h>
- #include "CConnectionPoint.h"
- #include "CCPContainer.h"
- #include "CError.h"
- #include "CLabelError.h"
- #include "BDUtils.h"
- #include "rotate.h"
- #include <ctype.h>
- #include <math.h>
- #include <stdio.h>
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::CLabelControl
- //
- // Constructor
- //
-
- CLabelControl::CLabelControl(void) : CBaseControl()
- {
- const Rect nullRect = { 0, 0, 0, 0 };
-
- // protected:
- mMainOffscreenGWorld = NULL;
- mPixOffscreenPixMap = NULL;
- mRectOffscreenBounds = nullRect;
-
- // user spec'd properties:
- mAngle = 0;
- mAlignment = 4;
- mBackStyle = 1;
- mBackColor = RGB_GRAY;
- strcpy(mCaption, "Default String");
- strcpy(mFontName, "Times");
- mFontBold = 0;
- mFontItalic = 0;
- mFontUnderline = 0;
- mFontStrikeout = 0;
- mFontSize = 18;
- mForeColor = RGB_BLACK;
- mMode = 0;
- mRotateBy = 0; // don't rotate when clicked, by default
-
- strcpy((char*) mID[1], "Label");
- mID[0] = strlen("Label");
-
- CCPContainer* containerObj = nil;
-
- // Create the new connection point container object
- containerObj = new CCPContainer(NUM_CONNECTIONS);
-
- // Snag the interface pointer
- if (containerObj)
- containerObj->QueryInterface(IID_IConnectionPointContainer, &mCPContainerP);
-
- // if we have a container object, allocate the connection points
- if (mCPContainerP)
- // We support 1 connection point
- containerObj->AddConnectionPoint(IID_IDoMenuEvents);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::~CLabelControl
- //
- // Destructor
- //
-
- CLabelControl::~CLabelControl(void)
- {
- // clean up offscreen world
- if (mMainOffscreenGWorld != NULL)
- {
- ::DisposeGWorld(mMainOffscreenGWorld);
- mMainOffscreenGWorld = NULL;
- mPixOffscreenPixMap = NULL;
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::IUnknown::QueryInterface
- //
- // Returns a pointer to the specified interface on a component to which a
- // client currently holds an interface pointer.
- //
-
- STDMETHODIMP
- CLabelControl::QueryInterface(REFIID inRefID, void** outObj)
- {
- HRESULT resultCode = ResultFromScode(E_NOINTERFACE); // init it cause I'm anal
-
- if (inRefID == IID_IBindStatusCallback)
- {
- resultCode = CBaseBindStatusCallback::QueryInterface(inRefID, outObj);
- }
-
- else if (inRefID == IID_IDoMenuEvents) // an outgoing interface
- {
- *outObj = (void*) (IDoMenuEvents*) this;
- AddRef();
-
- resultCode = ResultFromScode(S_OK);
- }
- else
- {
- resultCode = CBaseControl::QueryInterface(inRefID, outObj);
- }
- return resultCode;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::IControl::Draw
- //
- // Context the drawing context for ActiveX - includes the port
- //
- // Draw the label object.
- //
-
- STDMETHODIMP
- CLabelControl::Draw(THIS_ DrawContext* Context)
- {
- if (Context->DrawAspect != DVASPECT_CONTENT)
- return ResultFromScode(DV_E_DVASPECT);
-
- this->PrepareOffscreenWorld(Context); // get the main offscreen world setup and ready
-
- // get the offscreen bitmap
- BitMap* offscreenBitMap = this->GetOffscreenBitMap();
-
- // set the user selectable font properties
- this->SetFontParams(mMainOffscreenGWorld);
-
- // draw the text in the label
- this->RenderLabelControl();
-
- // Move it
- this->MoveOnScreen(offscreenBitMap, Context);
-
- // unlock, and unload
- this->ReleaseOffscreenBitMap(offscreenBitMap);
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::IControl::DoMouse
- //
-
- STDMETHODIMP CLabelControl::DoMouse(THIS_ MouseEventType inMouseET, PlatformEvent* inEvent)
- {
- switch (inMouseET)
- {
- case MouseDown:
- {
- // If the user has set a rotateby parameter, then rotate when we click.
- if ( mRotateBy != 0 )
- {
- // adjust the rotation angle -- we only handle (0 <= mRotateBy <= 360)
- mAngle += mRotateBy;
- mAngle %= fullRevolution; // Limit it to less than a revolution
-
- // get the current drawing environment
- DrawContext context = {(PortType) 0};
- mContainerSiteP->AcquireContext(mActiveContext->GetContextID(), &context);
-
- // draw
- Draw(&context);
-
- // reset the drawing environment
- mContainerSiteP->ReleaseContext(&context);
- }
- break;
- }
-
- case MouseEnter:
- {
- FireEvent(IID_IDoMenuEvents, DISPID_POPUP, inEvent);
- break;
- }
-
- case MouseUp:
- // We don't do anything for a mouse up event, since we handle
- // it with the mouse down.
- break;
- }
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::IPersistPropertyBag::Load
- //
- // PropBag container that holds all the properties passed in
- // ErrorLog ptr to an error log
- //
- // Sets the data members that represent the user definable properties from the URL.
- //
-
- STDMETHODIMP CLabelControl::Load(IPropertyBag* PropBag, IErrorLog* ErrorLog)
- {
- SCODE theSCode = LoadTextState(PropBag, ErrorLog);
- return ResultFromScode(theSCode);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::IPersistPropertyBag::LoadTextState
- //
- // pPropertyBag container that holds all the properties passed in
- // pErrorLog ptr to an error log
- //
- // Sets the data members that represent the user definable properties from the container stream.
- //
-
- STDMETHODIMP CLabelControl::LoadTextState(IPropertyBag *pPropertyBag,IErrorLog *pErrorLog)
- {
- const long maxLength = 256;
- char propertyString[MAX_PROPERTY_STRING_LENGTH];
-
- // try to load in each property. if we can't get it, then leave
- // things at the default.
-
- // The rotation angle
- if (::LoadPropertyString(pPropertyBag, "angle", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- mAngle = atoi(propertyString);
- mAngle %= fullRevolution; // limit to: 0 <= mAngle <= 360
-
- // The caption alignment
- if (::LoadPropertyString(pPropertyBag, "alignment", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- mAlignment = atoi(propertyString);
-
- // The backgroung property
- if (::LoadPropertyString(pPropertyBag, "backstyle", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- mBackStyle = atoi(propertyString);
-
- // The background color
- if (::LoadPropertyString(pPropertyBag, "backcolor", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- this->LoadColor(&mBackColor, propertyString);
-
- // The caption string
- if (::LoadPropertyString(pPropertyBag, "caption", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- strcpy(mCaption, propertyString);
-
- // The fontname string
- if (::LoadPropertyString(pPropertyBag, "fontname", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- strcpy(mFontName, propertyString);
-
- // Is the caption font bold style? -- 1, y, or Y means "YES" (anything else, i.e. 0, n, or N means "NO")
- if (::LoadPropertyString(pPropertyBag, "fontbold", propertyString, maxLength, pErrorLog))
- mFontBold = ((propertyString[0] == '1') || (propertyString[0] == 'y')|| (propertyString[0] == 'Y'));
-
- // Is the caption font italic style? -- 1, y, or Y means "YES" (anything else, i.e. 0, n, or N means "NO")
- if (::LoadPropertyString(pPropertyBag, "fontitalic", propertyString, maxLength, pErrorLog))
- mFontItalic = ((propertyString[0] == '1') || (propertyString[0] == 'y')|| (propertyString[0] == 'Y'));
-
- // Is the caption font underline style? -- 1, y, or Y means "YES" (anything else, i.e. 0, n, or N means "NO")
- if (::LoadPropertyString(pPropertyBag, "fontunderline", propertyString, maxLength, pErrorLog))
- mFontUnderline = ((propertyString[0] == '1') || (propertyString[0] == 'y')|| (propertyString[0] == 'Y'));
-
- // Is the caption font strikeout style? -- 1, y, or Y means "YES" (anything else, i.e. 0, n, or N means "NO")
- if (::LoadPropertyString(pPropertyBag, "fontstrikeout", propertyString, maxLength, pErrorLog))
- mFontStrikeout = ((propertyString[0] == '1') || (propertyString[0] == 'y')|| (propertyString[0] == 'Y'));
-
- // The font size
- if (::LoadPropertyString(pPropertyBag, "fontsize", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- mFontSize = atoi(propertyString);
-
- // The foreground color
- if (::LoadPropertyString(pPropertyBag, "forecolor", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- this->LoadColor(&mForeColor, propertyString);
-
- // The text rendering mode
- if (::LoadPropertyString(pPropertyBag, "mode", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- mMode = atoi(propertyString);
-
- // Rotate on click mode.
- if (::LoadPropertyString(pPropertyBag, "rotateby", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- mRotateBy = atoi(propertyString);
-
- // The object name of the label
- if (::LoadPropertyString(pPropertyBag, "sourceobjecttag_", propertyString, MAX_PROPERTY_STRING_LENGTH, pErrorLog))
- {
- strcpy((char*)(&mID[1]), propertyString);
- mID[0] = strlen(propertyString);
- }
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::FireEvent
- //
-
- STDMETHODIMP
- CLabelControl::FireEvent(REFIID RefID, long EventID, PlatformEvent* Event)
- {
- IEnumConnectionPoints* enumCP;
- IEnumConnections* enumC;
- CONNECTDATA connectData;
- IUnknown* eventTarget;
- IConnectionPoint* connectionPoint;
-
- // Get an enumerator for the connection points
- if (SUCCEEDED(mCPContainerP->EnumConnectionPoints(&enumCP)))
- {
- // Loop through all the connection points for this control
- while (enumCP->Next(1, &connectionPoint, nil) == NOERROR)
- {
- // Get all the connections for this connection point
- if (SUCCEEDED(connectionPoint->EnumConnections(&enumC)))
- {
- // Loop through all the connections for this connection point
- while (enumC->Next(1, &connectData, nil) == NOERROR)
- {
- // Get the interface implementation for this connection
- // if successful, fire the event
- if (SUCCEEDED(connectData.pUnk->QueryInterface(RefID, (void**) &eventTarget)))
- FireOneEvent(RefID, EventID, eventTarget, Event);
- }
-
- // Release the enumerator
- enumC->Release();
- }
- }
-
- enumCP->Release();
- }
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::CEventSender::FireOneEvent
- //
-
- STDMETHODIMP
- CLabelControl::FireOneEvent(REFIID /*RefID*/, long EventID, IUnknown* EventTarget, PlatformEvent* Event)
- {
- IDoMenuEvents* popTarget = (IDoMenuEvents*) EventTarget;
- IUnknown* unk;
-
- this->QueryInterface(IID_IUnknown, (void**) &unk);
-
- switch (EventID)
- {
- case DISPID_POPUP:
- popTarget->Popup(unk, Event);
- break;
- }
-
- return ResultFromScode(S_OK);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::LoadColor
- //
- //
- // theColor an RGBColor that defines the color tuple exactly (i.e., not indexed)
- // colorString a string with a color in it repesented in ASCII
- //
- // Sets the color data member based on the value of the user definable property.
- //
-
- Boolean CLabelControl::LoadColor(RGBColor * theColor, char * colorString)
- {
- Boolean didSet = true;
-
- for (short i = 0; i < strlen(colorString); i++)
- tolower(colorString[i]);
-
- if (streq(colorString, "black"))
- *theColor = RGB_BLACK;
- else if (streq(colorString, "white"))
- *theColor = RGB_WHITE;
- else if (streq(colorString, "red"))
- *theColor = RGB_RED;
- else if (streq(colorString, "green"))
- *theColor = RGB_GREEN;
- else if (streq(colorString, "blue"))
- *theColor = RGB_BLUE;
- else if (streq(colorString, "cyan"))
- *theColor = RGB_CYAN;
- else if (streq(colorString, "magenta"))
- *theColor = RGB_MAGENTA;
- else if (streq(colorString, "yellow"))
- *theColor = RGB_YELLOW;
- else
- {
- didSet = false; // reverse Boolean logic -- false unless we succeed
-
- // We're expecting a 32-bit hex RGB value in the format #00bbggrr.
- //
- // NOTE: To be compatible with Windows, if the high-order bit is set,
- // the low-order byte is supposed to be treated as a system color index.
- // We'll punt on this for now.
-
- Boolean punt = false;
-
- // sanity check on string format. #bbggrr, #0bbggrr, or #00bbggrr.
- int len = strlen(colorString);
- if ((colorString[0] == '#') && (len >= 7) && (len <= 9))
- {
- // if len == 9, the input may be trying to set the high-order
- // bit. Check for this and punt if so.
- if (len == 9)
- {
- char * sHi = "0x??";
- short iHi = 0;
-
- strncat(sHi, colorString, 2);
- sscanf(sHi, "%hx", &iHi);
-
- punt = iHi & 0x40;
- }
-
- if (! punt) // if we're NOT setting hi-order bit...
- {
- const int mostSignificantBits = 8; // amount to shift to move a byte
- const int numComponents = 3; // number of array components - one ea for R,G & B
- const int redPos = 2; // array position for component
- const int greenPos = 1; // array position for component
- const int bluePos = 0; // array position for component
-
- unsigned short desiredColorArray[numComponents]; // a COLORREF, as an array
-
- for (short i = 0, pos = len-2; i < numComponents; i++, pos -= 2)
- {
- char * sColor = "0x??";
- short aShort = 0;
- strncpy(&sColor[2], &colorString[pos], 2);
- sscanf(sColor, "%hx", &aShort);
- ASSERT((aShort <= 0xff), "Range check error!");
- desiredColorArray[i] = aShort << mostSignificantBits;// move the color component value into the ms bits
- }
-
- // return the color that we went to all that trouble to set
- theColor->red = (unsigned short) desiredColorArray[redPos];
- theColor->green = (unsigned short) desiredColorArray[greenPos];
- theColor->blue = (unsigned short) desiredColorArray[bluePos];
-
- // success, so tell the world
- didSet = true;
- }
- }
- }
-
- return didSet;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::PrepareOffscreenWorld
- //
- // Context the drawing context for ActiveX - includes the port
- //
- // Creates the offscreen gworld that is the current display.
- //
-
- void CLabelControl::PrepareOffscreenWorld(const DrawContext* Context)
- {
- try
- {
- // get the current drawing environment
-
- // If there's already an offscreen GWorld, get rid of it.
- if (mMainOffscreenGWorld != nil)
- {
- DisposeGWorld(mMainOffscreenGWorld);
- mMainOffscreenGWorld = nil;
- }
-
- // Define the size of the GWorld's bounding boxes -- same size as onscreen
- short rightBounds = Context->Location.right - Context->Location.left;
- short bottomBounds = Context->Location.bottom - Context->Location.top;
- SetRect(&mRectOffscreenBounds, 0, 0, rightBounds, bottomBounds);
-
- // Allocate a new GWorld for the offscreen drawing and store its PixMap.
- GDHandle currDevice = ::GetGDevice();
- short targetDepth = (**(**currDevice).gdPMap).pixelSize; // how many pixels deep are we?
- QDErr err = ::NewGWorld(&mMainOffscreenGWorld, targetDepth, &mRectOffscreenBounds, 0, nil, 0);
-
- if (!err)
- {
- mPixOffscreenPixMap = ::GetGWorldPixMap(mMainOffscreenGWorld);
-
- // we should now have a gworld
- if (mMainOffscreenGWorld == nil || mPixOffscreenPixMap == nil)
- throw CLabelError(CONTROL_GWORLD_ALLOCATION_ERROR, this);
-
- // Clear the image
- this->ClearDisplay();
- }
- }
-
- // error handling
- catch (CLabelError &labelError)
- {
- labelError.HandleError();
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::ClearDisplay
- //
- // No params no parameters are passed or returned
- //
- // Erases the main offscreen world to the background color passed in the properties
- //
-
- void CLabelControl::ClearDisplay(void)
- {
- // Store the current port and device before switching to the offscreen world.
- CGrafPtr currentPort;
- GDHandle currentDevice;
- ::GetGWorld(¤tPort, ¤tDevice);
-
- // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
- ::SetGWorld(mMainOffscreenGWorld, nil);
-
- // Set the background color before we erase
- ::RGBBackColor(&mBackColor);
-
- // Erase the PixMap's bounding box in the GWorld.
- ::EraseRect(&mRectOffscreenBounds);
-
- // restore the original port and device
- ::SetGWorld(currentPort, currentDevice);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::MoveOnScreen
- //
- // offscreenBitMap a PixMap or BitMap pointer
- // Context the drawing context for ActiveX - includes the port
- //
- // Computes the size of the rect needed to hold the rotated rect.
- //
-
- void CLabelControl::MoveOnScreen(const BitMap* /*offscreenBitMap*/, const DrawContext* Context)
- {
- // Set the colors
- ::RGBForeColor(&RGB_BLACK);
- ::RGBBackColor(&RGB_WHITE);
-
- // actually move the bits
- ::CopyBits((BitMap*)*mPixOffscreenPixMap, &(Context->Port->portBits), &mRectOffscreenBounds, &Context->Location, srcCopy, NULL);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::GetOffscreenBitMap
- //
- // returns BitMap a PixMap or BitMap pointer
- //
- // Returns a BitMap/PixMap that is part of the offscreen world - ready to draw into.
- //
-
- BitMap * CLabelControl::GetOffscreenBitMap(void)
- {
- // sanity check
- ASSERT((mPixOffscreenPixMap != NULL), "NULL offscreen pixmap!");
-
- // Lock n load the pixMap handle 'till we're done with it
- ::LockPixels(mPixOffscreenPixMap);
-
- // lock handle so it does not float on us
- ::HLock((Handle)mPixOffscreenPixMap);
-
- // Note the bitmap, now that we've locked n loaded
- BitMap* offscreenBitMap = (BitMap *)(*mPixOffscreenPixMap);
- ASSERT((offscreenBitMap != NULL), "NULL offscreen bitmap!");
-
- return offscreenBitMap;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::ReleaseOffscreenBitMap
- //
- // offscreenBitMap an offscreenBitMap that we are through with and would like to purge.
- //
- // Unlocks handles and pixels in preparation for disposing of a GWorld
- //
-
- void CLabelControl::ReleaseOffscreenBitMap(BitMap * offscreenBitMap)
- {
-
- // we are done with this handle so let it float
- ::HUnlock((Handle)mPixOffscreenPixMap);
-
- // Release the pixMap handle
- ::UnlockPixels(mPixOffscreenPixMap);
-
- // Set this to NULL just as a safety factor
- offscreenBitMap = NULL;
- }
-
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // P R I V A T E D R A W I N G S U P P O R T
- //
- ///////////////////////////////////////////////////////////////////////////////
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::SetFontParams
- //
- // theGWorld a GWorld that we want to set up the font parameters in
- //
- // This routine sets the GWorld font params up based on the properties that were passed.
- //
-
-
- void CLabelControl::SetFontParams(GWorldPtr theGWorld)
- {
- // switch to the offscreen GWorld to set up the font stuff
- CGrafPtr currentPort;
- GDHandle currentDevice;
- ::GetGWorld(¤tPort, ¤tDevice);
-
- ::SetGWorld(theGWorld, NULL);
-
- // set the font info up from what was passed into us
- if (mFontBold) TextFace(bold);
- if (mFontItalic) TextFace(italic);
- if (mFontUnderline) TextFace(underline);
-
- // convert fontname to a pascal string
- Str255 fontName;
- strcpy((char *)fontName, mFontName);
- c2pstr((char *)fontName);
-
- short familyID = 0;
- ::GetFNum(fontName, &familyID);
- if (familyID == 0)
- ::TextFont(applFont);
- else
- ::TextFont(familyID);
- ::TextSize(this->mFontSize);
- ::TextMode(srcCopy);
-
- ::GetFontInfo(&mFontInfo); // save off the current font info
-
- // Set the port and device back to the original
- ::SetGWorld(currentPort, currentDevice);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::GetTextSize
- //
- // aString a string of the pascal type
- // textSize the size of a Rect expressed as the bottom-right corner
- //
- // Computes the size of a rect needed to hold aString (assumes that the GWorld
- // has been init'd to the correct font and styles).
- //
-
- void CLabelControl::GetTextSize(const StringPtr aString, Point * textSize)
- {
- // Store the current port and device before switching to the offscreen world.
- CGrafPtr currentPort;
- GDHandle currentDevice;
- ::GetGWorld(¤tPort, ¤tDevice);
-
- // Switch to the offscreen GWorld so that the string width is accurate
- ::SetGWorld(mMainOffscreenGWorld, NULL);
-
- textSize->v = mFontInfo.ascent + mFontInfo.descent; // compute height
-
- textSize->h = StringWidth(aString); // compute width
-
- // restore the saved off port
- ::SetGWorld(currentPort, currentDevice);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::RenderLabelControl
- //
- // No params no parameters are passed or returned
- //
- // Actually does the drawing of the label. It creates the content GWorld. Then
- // rotates it as needed. Then blits it into the offscreen PixMap (data member).
- //
-
- void CLabelControl::RenderLabelControl(void)
- {
- Point contentSize = {0, 0}; // nil going in -- comes back to us with the size of the bitmap
- GWorldPtr contentGWorld = nil; // init to nil to satisfy the compiler
- GWorldPtr scratchGWorld = nil; // ditto
- short rotationAngle;
- CGrafPtr currentPort; // use for saving off curr GWorld
- GDHandle currentDevice;
-
- // build a GWorld just big enough for the string and then draw draw string into it
- QDErr theErr = CreateContent(&contentSize, contentGWorld);
- PixMapHandle contentPixMap = ::GetGWorldPixMap(contentGWorld);
-
- if(mAngle > quarterRevolution) // 360 < angle < 90
- {
- short preRotate = mAngle / quarterRevolution; // how many times must we rotate by 90?
- rotationAngle = mAngle % quarterRevolution; // reduce angle - e.g., how much more do we rotate?
-
- switch(preRotate) // number of times to rotate by 90 degrees (i.e., 1 for 2nd quad, 2 for 3rd and 3 for 4th)
- {
- case 1:
- {
- GWorldPtr preRotateGWorld = nil; // init to nil to satisfy the compiler
- theErr = Rotate90(contentGWorld, preRotateGWorld);
- ASSERT(theErr == noErr, "failed to pre-rotate by 90");
-
- // blow away previous content and recreate it
- ReleaseOffscreenBitMap((BitMap*)&contentPixMap);
- ::DisposeGWorld(contentGWorld); // we have rotated so now we can blow it away
- contentGWorld = nil; // just to make double sure
-
- // Recreate content GWorld:
- Rect preRotateRect = (**((CGrafPort)*preRotateGWorld).portPixMap).bounds; // how many pixels deep are we?
- try
- {
- theErr = ::NewGWorld(&contentGWorld, twoHundredFiftySixColorsDepth, &preRotateRect, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to recreate content GWorld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- // prepare to copy the pre-rotated version into the new content
- PixMapHandle preRotatePixMap = ::GetGWorldPixMap(preRotateGWorld);
- ::LockPixels(preRotatePixMap);
- ::HLock((Handle)preRotatePixMap);
-
- contentPixMap = ::GetGWorldPixMap(contentGWorld);
- ::LockPixels(contentPixMap);
- ::HLock((Handle)contentPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice);
-
- ::SetGWorld(contentGWorld, nil); // Switch to the scratch GWorld
-
- ::RGBForeColor(&RGB_BLACK);
- ::RGBBackColor(&RGB_WHITE);
- // now copy back into the (new) content
- ::CopyBits((BitMap *)(*preRotatePixMap), (BitMap *)(*contentPixMap),
- &(**preRotatePixMap).bounds, &(**contentPixMap).bounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore GWorld
-
- // reset the content size:
- contentSize.v = (**contentPixMap).bounds.bottom - (**contentPixMap).bounds.top;
- contentSize.h = (**contentPixMap).bounds.right - (**contentPixMap).bounds.left;
-
- ::DisposeGWorld(preRotateGWorld);
-
- // rotate the content GWorld and return a rotatedGWorld (the new GWorld is alloc'd
- // by the rotation routine but we must dispose of it when completed drawing
- GWorldPtr rotatedGWorld = nil; // init to nil to satisfy the compiler
- theErr = rotate(contentPixMap, contentSize.v, contentSize.h, DegressToRadians((double)rotationAngle), mBackColor, rotatedGWorld);
- ASSERT(theErr == noErr, "rotate() failed - probably low mem!");
- if(theErr != noErr)
- throw CLabelError(ROTATION_FAILED_ERROR, this);
-
- // now compute the alignment our content GWorld within the label GWorld
- PixMapHandle rotatedPixMap = ::GetGWorldPixMap(rotatedGWorld);
- Rect contentBounds = (**rotatedPixMap).bounds; // get a copy of the rotated rect
- ComputeAlignmentRect(contentBounds, mRectOffscreenBounds);
-
- // Create a scratch pixmap at 8 bits deep so that we can assemble the entire thing
- // in the 256 color depth. Then we can copy the entire 256 color into the final
- // GWorld at the target bitmap color depth.
- theErr = ::NewGWorld(&scratchGWorld, twoHundredFiftySixColorsDepth, &mRectOffscreenBounds, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to alloc scratch GWorrld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- PixMapHandle scratchPixMap = ::GetGWorldPixMap(scratchGWorld);
- ::LockPixels(scratchPixMap);
- ::HLock((Handle)scratchPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(scratchGWorld, nil); // Set the port and device back to the original
-
- ::RGBBackColor(&mBackColor); // Set the background color before we erase
- ::EraseRect(&(**scratchPixMap).bounds); // Erase the PixMap's bounding box in the GWorld.
-
- ::RGBForeColor(&RGB_BLACK);
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*rotatedPixMap), (BitMap *)(*scratchPixMap),
- &(**rotatedPixMap).bounds, &contentBounds, srcCopy, NULL);
-
- ::DisposeGWorld(rotatedGWorld); // cleanup the rotation artifacts
-
- ::SetGWorld(currentPort, currentDevice); // restore to the previous GWorld
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(mMainOffscreenGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
- // copy the content into the label
- ::RGBBackColor(&mBackColor); // Set the background color before we erase
- ::EraseRect(&(**mPixOffscreenPixMap).bounds); // Erase the PixMap's bounding box in the GWorld.
-
- ::RGBForeColor(&RGB_BLACK);
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*scratchPixMap), (BitMap *)(*mPixOffscreenPixMap),
- &(**scratchPixMap).bounds, &mRectOffscreenBounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore the port and device back to the original
-
- ::DisposeGWorld(scratchGWorld); // cleanup the scratch artifacts
- ::DisposeGWorld(contentGWorld);
- }// try
-
- // error handling
- catch (CLabelError &labelError)
- {
- labelError.HandleError();
- }
- break;
- }// case 1
-
- case 2:
- {
- try
- {
- GWorldPtr preRotateGWorld = nil; // init to nil to satisfy the compiler
- theErr = Rotate90(contentGWorld, preRotateGWorld);
- ASSERT(theErr == noErr, "failed to pre-rotate by 180");
-
- // blow away previous content and recreate it
- ReleaseOffscreenBitMap((BitMap*)&contentPixMap);
- ::DisposeGWorld(contentGWorld);
- contentGWorld = nil; // just to make double sure
-
- // Recreate content GWorld:
- Rect preRotateRect = (**((CGrafPort)*preRotateGWorld).portPixMap).bounds; // how many pixels deep are we?
-
- theErr = ::NewGWorld(&contentGWorld, twoHundredFiftySixColorsDepth, &preRotateRect, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to recreate content GWorld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- // prepare to copy the pre-rotated version into the new content
- PixMapHandle preRotatePixMap = ::GetGWorldPixMap(preRotateGWorld);
- ::LockPixels(preRotatePixMap);
- ::HLock((Handle)preRotatePixMap);
-
- contentPixMap = ::GetGWorldPixMap(contentGWorld);
- ::LockPixels(contentPixMap);
- ::HLock((Handle)contentPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(contentGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- // now copy back into the (new) content
- ::CopyBits((BitMap *)(*preRotatePixMap), (BitMap *)(*contentPixMap),
- &(**preRotatePixMap).bounds, &(**contentPixMap).bounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore to the previous GWorld
-
- // reset the content size:
- contentSize.v = (**contentPixMap).bounds.bottom - (**contentPixMap).bounds.top;
- contentSize.h = (**contentPixMap).bounds.right - (**contentPixMap).bounds.left;
-
- ::DisposeGWorld(preRotateGWorld);
- preRotateGWorld = nil; // re-init to just to make sure
- theErr = Rotate90(contentGWorld, preRotateGWorld);
- ASSERT(theErr == noErr, "failed to pre-rotate by 180");
-
- // now we copy it back again:
- // blow away previous content and recreate it
- ReleaseOffscreenBitMap((BitMap*)&contentPixMap);
- ::DisposeGWorld(contentGWorld);
- contentGWorld = nil; // just to make double sure
-
- // Recreate content GWorld:
- preRotateRect = (**((CGrafPort)*preRotateGWorld).portPixMap).bounds; // how many pixels deep are we?
-
- theErr = ::NewGWorld(&contentGWorld, twoHundredFiftySixColorsDepth, &preRotateRect, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to recreate content GWorld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- // prepare to copy the pre-rotated version into the new content
- preRotatePixMap = ::GetGWorldPixMap(preRotateGWorld);
- ::LockPixels(preRotatePixMap);
- ::HLock((Handle)preRotatePixMap);
-
- contentPixMap = ::GetGWorldPixMap(contentGWorld);
- ::LockPixels(contentPixMap);
- ::HLock((Handle)contentPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(contentGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- // now copy back into the (new) content
- ::CopyBits((BitMap *)(*preRotatePixMap), (BitMap *)(*contentPixMap),
- &(**preRotatePixMap).bounds, &(**contentPixMap).bounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore to the previous GWorld
-
- // reset the content size:
- contentSize.v = (**contentPixMap).bounds.bottom - (**contentPixMap).bounds.top;
- contentSize.h = (**contentPixMap).bounds.right - (**contentPixMap).bounds.left;
-
- ::DisposeGWorld(preRotateGWorld);
- preRotateGWorld = nil; // re-init to just to make sure
-
- // rotate the content GWorld and return a rotatedGWorld (the new GWorld is alloc'd
- // by the rotation routine but we must dispose of it when completed drawing
- GWorldPtr rotatedGWorld = nil; // init to nil to satisfy the compiler
- theErr = rotate(contentPixMap, contentSize.v, contentSize.h, DegressToRadians((double)rotationAngle), mBackColor, rotatedGWorld);
- ASSERT(theErr == noErr, "rotate() failed - probably low mem!");
- if(theErr != noErr)
- throw CLabelError(ROTATION_FAILED_ERROR, this);
-
- // now compute the alignment our content GWorld within the label GWorld
- PixMapHandle rotatedPixMap = ::GetGWorldPixMap(rotatedGWorld);
- Rect contentBounds = (**rotatedPixMap).bounds; // get a copy of the rotated rect
- ComputeAlignmentRect(contentBounds, mRectOffscreenBounds);
-
- // Create a scratch pixmap at 8 bits deep so that we can assemble the entire thing
- // in the 256 color depth. Then we can copy the entire 256 color into the final
- // GWorld at the target bitmap color depth.
- theErr = ::NewGWorld(&scratchGWorld, twoHundredFiftySixColorsDepth, &mRectOffscreenBounds, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to alloc scratch GWorrld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- PixMapHandle scratchPixMap = ::GetGWorldPixMap(scratchGWorld);
- ::LockPixels(scratchPixMap);
- ::HLock((Handle)scratchPixMap);
-
- // Store the current port and device before switching to the offscreen world.
- ::GetGWorld(¤tPort, ¤tDevice);
-
- ::SetGWorld(scratchGWorld, nil); // Switch to the scratch GWorld and lock the offscreen buffer in memory.
- ::RGBBackColor(&mBackColor); // Set the background color before we erase
-
- ::EraseRect(&(**scratchPixMap).bounds); // Erase the PixMap's bounding box in the GWorld.
-
- ::RGBForeColor(&RGB_BLACK);
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*rotatedPixMap), (BitMap *)(*scratchPixMap),
- &(**rotatedPixMap).bounds, &contentBounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // Set the port and device back to the original
-
- ::DisposeGWorld(rotatedGWorld); // cleanup the rotation artifacts
-
-
- ::SetGWorld(mMainOffscreenGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
- // copy the content into the label
- ::RGBForeColor(&RGB_BLACK);
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*scratchPixMap), (BitMap *)(*mPixOffscreenPixMap),
- &(**scratchPixMap).bounds, &mRectOffscreenBounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // Set the port and device back to the original
-
- ::DisposeGWorld(scratchGWorld); // cleanup the scratch artifacts
- ::DisposeGWorld(contentGWorld);
- }// try
-
- // error handling
- catch (CLabelError &labelError)
- {
- labelError.HandleError();
- }
-
- break;
- }// case 2
-
- case 3:
- {
- try
- {
- GWorldPtr preRotateGWorld = nil; // init to nil to satisfy the compiler
- theErr = Rotate90(contentGWorld, preRotateGWorld); // rotate for 90
- ASSERT(theErr == noErr, "failed to pre-rotate by 180");
-
- // blow away previous content and recreate it
- ReleaseOffscreenBitMap((BitMap*)&contentPixMap);
- ::DisposeGWorld(contentGWorld);
- contentGWorld = nil; // just to make double sure
-
- // Recreate content GWorld:
- Rect preRotateRect = (**((CGrafPort)*preRotateGWorld).portPixMap).bounds; // how many pixels deep are we?
-
- theErr = ::NewGWorld(&contentGWorld, twoHundredFiftySixColorsDepth, &preRotateRect, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to recreate content GWorld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- // prepare to copy the pre-rotated version into the new content
- PixMapHandle preRotatePixMap = ::GetGWorldPixMap(preRotateGWorld);
- ::LockPixels(preRotatePixMap);
- ::HLock((Handle)preRotatePixMap);
-
- contentPixMap = ::GetGWorldPixMap(contentGWorld);
- ::LockPixels(contentPixMap);
- ::HLock((Handle)contentPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(contentGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- // now copy back into the (new) content
- ::CopyBits((BitMap *)(*preRotatePixMap), (BitMap *)(*contentPixMap),
- &(**preRotatePixMap).bounds, &(**contentPixMap).bounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore to the previous GWorld
-
- // reset the content size:
- contentSize.v = (**contentPixMap).bounds.bottom - (**contentPixMap).bounds.top;
- contentSize.h = (**contentPixMap).bounds.right - (**contentPixMap).bounds.left;
-
- ::DisposeGWorld(preRotateGWorld);
- preRotateGWorld = nil; // re-init to just to make sure
- theErr = Rotate90(contentGWorld, preRotateGWorld); // rotate 2nd time for 180
- ASSERT(theErr == noErr, "failed to pre-rotate by 180");
-
- // now we copy it back again:
- // blow away previous content and recreate it
- ReleaseOffscreenBitMap((BitMap*)&contentPixMap);
- ::DisposeGWorld(contentGWorld);
- contentGWorld = nil; // just to make double sure
-
- // Recreate content GWorld:
- preRotateRect = (**((CGrafPort)*preRotateGWorld).portPixMap).bounds; // how many pixels deep are we?
-
- theErr = ::NewGWorld(&contentGWorld, twoHundredFiftySixColorsDepth, &preRotateRect, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to recreate content GWorld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- // prepare to copy the pre-rotated version into the new content
- preRotatePixMap = ::GetGWorldPixMap(preRotateGWorld);
- ::LockPixels(preRotatePixMap);
- ::HLock((Handle)preRotatePixMap);
-
- contentPixMap = ::GetGWorldPixMap(contentGWorld);
- ::LockPixels(contentPixMap);
- ::HLock((Handle)contentPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(contentGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- // now copy back into the (new) content
- ::CopyBits((BitMap *)(*preRotatePixMap), (BitMap *)(*contentPixMap),
- &(**preRotatePixMap).bounds, &(**contentPixMap).bounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore to the previous GWorld
-
- // reset the content size:
- contentSize.v = (**contentPixMap).bounds.bottom - (**contentPixMap).bounds.top;
- contentSize.h = (**contentPixMap).bounds.right - (**contentPixMap).bounds.left;
-
- ::DisposeGWorld(preRotateGWorld);
- preRotateGWorld = nil; // re-init to just to make sure
- theErr = Rotate90(contentGWorld, preRotateGWorld); // rotate third time for 270
- ASSERT(theErr == noErr, "failed to pre-rotate by 270");
-
- // now we copy it back again:
- // blow away previous content and recreate it
- ReleaseOffscreenBitMap((BitMap*)&contentPixMap);
- ::DisposeGWorld(contentGWorld);
- contentGWorld = nil; // just to make double sure
-
- // Recreate content GWorld:
- preRotateRect = (**((CGrafPort)*preRotateGWorld).portPixMap).bounds; // how many pixels deep are we?
-
- theErr = ::NewGWorld(&contentGWorld, twoHundredFiftySixColorsDepth, &preRotateRect, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to recreate content GWorld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- // prepare to copy the pre-rotated version into the new content
- preRotatePixMap = ::GetGWorldPixMap(preRotateGWorld);
- ::LockPixels(preRotatePixMap);
- ::HLock((Handle)preRotatePixMap);
-
- contentPixMap = ::GetGWorldPixMap(contentGWorld);
- ::LockPixels(contentPixMap);
- ::HLock((Handle)contentPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(contentGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- // now copy back into the (new) content
- ::CopyBits((BitMap *)(*preRotatePixMap), (BitMap *)(*contentPixMap),
- &(**preRotatePixMap).bounds, &(**contentPixMap).bounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore to the previous GWorld
-
- // reset the content size:
- contentSize.v = (**contentPixMap).bounds.bottom - (**contentPixMap).bounds.top;
- contentSize.h = (**contentPixMap).bounds.right - (**contentPixMap).bounds.left;
-
- ::DisposeGWorld(preRotateGWorld);
- preRotateGWorld = nil; // re-init to just to make sure
-
- // rotate the content GWorld and return a rotatedGWorld (the new GWorld is alloc'd
- // by the rotation routine but we must dispose of it when completed drawing
- GWorldPtr rotatedGWorld = nil; // init to nil to satisfy the compiler
- theErr = rotate(contentPixMap, contentSize.v, contentSize.h, DegressToRadians((double)rotationAngle), mBackColor, rotatedGWorld);
- ASSERT(theErr == noErr, "rotate() failed - probably low mem!");
- if(theErr != noErr)
- throw CLabelError(ROTATION_FAILED_ERROR, this);
-
- // now compute the alignment our content GWorld within the label GWorld
- PixMapHandle rotatedPixMap = ::GetGWorldPixMap(rotatedGWorld);
- Rect contentBounds = (**rotatedPixMap).bounds; // get a copy of the rotated rect
- ComputeAlignmentRect(contentBounds, mRectOffscreenBounds);
-
- // Create a scratch pixmap at 8 bits deep so that we can assemble the entire thing
- // in the 256 color depth. Then we can copy the entire 256 color into the final
- // GWorld at the target bitmap color depth.
- theErr = ::NewGWorld(&scratchGWorld, twoHundredFiftySixColorsDepth, &mRectOffscreenBounds, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to alloc scratch GWorrld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- PixMapHandle scratchPixMap = ::GetGWorldPixMap(scratchGWorld);
- ::LockPixels(scratchPixMap);
- ::HLock((Handle)scratchPixMap);
-
- // Store the current port and device before switching to the offscreen world.
- ::GetGWorld(¤tPort, ¤tDevice);
-
- ::SetGWorld(scratchGWorld, nil); // Switch to the scratch GWorld
- ::RGBBackColor(&mBackColor); // Set the background color before we erase
-
- ::EraseRect(&(**scratchPixMap).bounds); // Erase the PixMap's bounding box in the GWorld.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*rotatedPixMap), (BitMap *)(*scratchPixMap),
- &(**rotatedPixMap).bounds, &contentBounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice);// restore to the previous GWorld
-
- ::DisposeGWorld(rotatedGWorld); // cleanup the rotation artifacts
-
- ::SetGWorld(mMainOffscreenGWorld, nil); // Switch to the offscreen GWorld.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*scratchPixMap), (BitMap *)(*mPixOffscreenPixMap),
- &(**scratchPixMap).bounds, &mRectOffscreenBounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice);// Set the port and device back to the original
-
- ::DisposeGWorld(scratchGWorld); // cleanup the scratch artifacts
- ::DisposeGWorld(contentGWorld);
- }// try
-
- // error handling
- catch (CLabelError &labelError)
- {
- labelError.HandleError();
- }
-
- break;
- }// case 3
- }// switch(preRotate)
- }// if (mAngle > quarterRevolution)
- else
- {
- rotationAngle = mAngle; // did not have to pre-rotate so set to parameter
- }// else
-
-
- if(mAngle != 0 && mAngle <= quarterRevolution) // 0 < angle <= 90
- {
- try
- {
- // rotate the content GWorld and return a rotatedGWorld (the new GWorld is alloc'd
- // by the rotation routine but we must dispose of it when completed drawing
- GWorldPtr rotatedGWorld = nil; // init to nil to satisfy the compiler
- theErr = rotate(contentPixMap, contentSize.v, contentSize.h, DegressToRadians((double)mAngle), mBackColor, rotatedGWorld);
- ASSERT(theErr == noErr, "rotate() failed - probably low mem!");
- if(theErr != noErr)
- throw CLabelError(ROTATION_FAILED_ERROR, this);
-
- // now compute the alignment our content GWorld within the label GWorld
- PixMapHandle rotatedPixMap = ::GetGWorldPixMap(rotatedGWorld);
- Rect contentBounds = (**rotatedPixMap).bounds; // get a copy of the rotated rect
- ComputeAlignmentRect(contentBounds, mRectOffscreenBounds);
-
- // Create a scratch pixmap at 8 bits deep so that we can assemble the entire thing
- // in the 256 color depth. Then we can copy the entire 256 color into the final
- // GWorld at the target bitmap color depth.
- theErr = ::NewGWorld(&scratchGWorld, twoHundredFiftySixColorsDepth, &mRectOffscreenBounds, 0, nil, 0);
- ASSERT(theErr == noErr, "failed to alloc scratch GWorld");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- PixMapHandle scratchPixMap = ::GetGWorldPixMap(scratchGWorld);
- ::LockPixels(scratchPixMap);
- ::HLock((Handle)scratchPixMap);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(scratchGWorld, nil); // Switch to the offscreen GWorld
- ::RGBBackColor(&mBackColor); // Set the background color before we erase
-
- ::EraseRect(&((**scratchPixMap).bounds)); // Erase the PixMap's bounding box in the GWorld.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last pallette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- // copy the content into a 256 color version of the label
- ::CopyBits((BitMap *)(*rotatedPixMap), (BitMap *)(*scratchPixMap),
- &(**rotatedPixMap).bounds, &contentBounds, srcCopy, NULL);
-
- ::DisposeGWorld(rotatedGWorld); // cleanup the rotation artifacts
-
- ::SetGWorld(mMainOffscreenGWorld, nil); // Switch to the offscreen GWorld
-
- ::RGBBackColor(&mBackColor); // Set the background color before we erase
- ::EraseRect(&mRectOffscreenBounds); // Erase the PixMap's bounding box in the GWorld.
-
- ::RGBForeColor(&RGB_BLACK); // set the first and last palette colors before we copy
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*scratchPixMap), (BitMap *)(*mPixOffscreenPixMap),
- &(**scratchPixMap).bounds, &mRectOffscreenBounds, srcCopy, NULL);
- ::DisposeGWorld(scratchGWorld); // cleanup the scratch artifacts
-
- ::SetGWorld(currentPort, currentDevice); // Set the port and device back to the original
- }// try
-
- // error handling
- catch (CLabelError &labelError)
- {
- labelError.HandleError();
- }
-
- }// if(mAngle != 0 && mAngle <= 90)
- else if(mAngle == 0) // angle == 0 so we are not rotating -- just copy content into label
- {
- // now compute the alignment our content GWorld within the label GWorld
- Rect contentBounds = (**contentPixMap).bounds; // get a copy of the content rect
- ComputeAlignmentRect(contentBounds, mRectOffscreenBounds);
-
- ::GetGWorld(¤tPort, ¤tDevice); // Store the current port and device before switching to the offscreen world.
-
- ::SetGWorld(mMainOffscreenGWorld, nil); // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
-
- // Set the colors before we do a copybits so
- ::RGBForeColor(&RGB_BLACK);
- ::RGBBackColor(&RGB_WHITE);
-
- ::CopyBits((BitMap *)(*contentPixMap), (BitMap *)(*mPixOffscreenPixMap),
- &(**contentPixMap).bounds, &contentBounds, srcCopy, NULL);
-
- ::SetGWorld(currentPort, currentDevice); // restore to the previous GWorld
- }// else if(rotationAngle == 0)
-
- // DisposeGWorld(contentGWorld);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::ComputeAlignmentRect
- //
- // theContentRect the rect that is to be aligned
- // theLabelRect the parent rect (i.e., this one is stationary -- the other one moves)
- //
- // This routine aligns the contentRect inside theLabelRect. It does so
- // according to the parameter passed as mAlignment by the OCX. This operation
- // takes place on a rect that has been prepared and is ready to blit into
- // place (i.e., it is rotated already).
- //
-
- void CLabelControl::ComputeAlignmentRect(Rect &theContentRect, const Rect theLabelRect)
- {
- // compute the differences between rect sizes:
- short deltaVert = (theLabelRect.bottom - theLabelRect.top) - theContentRect.bottom;
- short deltaHoriz = (theLabelRect.right - theLabelRect.left) - theContentRect.right;
-
- // now compute the amount that we will offset the content rect by:
- Point offsetAmount;
-
- // do the horizontal coord first
- switch(mAlignment)
- {
- case 0:
- case 3:
- case 6: // left aligned
- offsetAmount.h = 0; // don't offset horiz
- break;
-
- case 1:
- case 4:
- case 7: // centered horizontally
- offsetAmount.h = deltaHoriz / 2; // offset by half the difference horiz
- break;
-
- case 2:
- case 5:
- case 8: // right aligned
- offsetAmount.h = deltaHoriz; // offset by the entire horiz difference
- break;
-
- default:
- throw CLabelError(CONTROL_BAD_ALIGNMENT_PARAM_ERROR, this);
- }
-
- // now the vertical coord
- switch(mAlignment)
- {
- case 0:
- case 1:
- case 2: // top aligned
- offsetAmount.v = 0; // don't offset vert
- break;
-
- case 3:
- case 4:
- case 5: // centered vertically
- offsetAmount.v = deltaVert / 2; // offset by half the difference vert
- break;
-
- case 6:
- case 7:
- case 8: // bottom aligned
- offsetAmount.v = deltaVert; // offset by the entire vert difference
- break;
-
- default:
- throw CLabelError(CONTROL_BAD_ALIGNMENT_PARAM_ERROR, this);
- }
-
- // now we can just offset the content rect:
- OffsetRect(&theContentRect, offsetAmount.h, offsetAmount.v);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::RotatedSize
- //
- // angDegrees the CCW angle in degrees from the horizontal
- // origSize the size of a Rect expressed as the bottom-right corner
- //
- // Computes the size of the rect needed to hold the rotated rect.
- //
-
- Point CLabelControl::RotatedSize(const double angDegrees, const Point origSize)
- {
- double angRadians = DegressToRadians(angDegrees);
- double compAngRadians = DegressToRadians(quarterRevolution - angDegrees);
- Point rotSize = { sin(angRadians) * origSize.h + cos(angRadians) * origSize.v, // v = sin(ø)w + cos(ø)h
- sin(compAngRadians) * origSize.h + cos(compAngRadians) * origSize.v }; // h same with angle = 90 - ø
- return rotSize;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::CreateContent
- //
- // textSize the size of a Rect that holds the caption expressed as
- // the bottom-right corner
- // contentGWorld a GWorld containing the caption (not rotated)
- //
- // Given a nil pointer to a GWorld return a GWorld setup with all the right params
- // and with the caption string drawn in it.
- //
-
- QDErr CLabelControl::CreateContent(Point* textSize, GWorldPtr &contentGWorld)
- {
- QDErr theErr;
- try
- {
- // Get the size of the Caption
- Point sizeCaption = {0, 0}; // nil point cause I'm anal
- Str255 strCaption; // temp holder for our string - we store it as a c-string
- strcpy((char *)strCaption, mCaption);
- c2pstr((char *)strCaption);
- this->GetTextSize(strCaption, &sizeCaption); // get the smallest rect to hold our text
- textSize->h = sizeCaption.h; // pass this back so we can use it later
- textSize->v = sizeCaption.v;
-
- const Rect contentBounds = { 0, 0, textSize->v, textSize->h };
- // alloc the output GWorld and save results of failure
- theErr = ::NewGWorld(&contentGWorld, twoHundredFiftySixColorsDepth , &contentBounds, 0, nil, 0);
- ASSERT(theErr == noErr, "alloc contentGWorld failed!");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- this->SetFontParams(contentGWorld);
-
- // Store the current port and device before switching to the offscreen world.
- CGrafPtr currentPort;
- GDHandle currentDevice;
- ::GetGWorld(¤tPort, ¤tDevice);
-
- // Switch to the offscreen GWorld and lock the offscreen buffer in memory.
- ::SetGWorld(contentGWorld, NULL);
- PixMapHandle contentPixMap = GetGWorldPixMap(contentGWorld);
- ::LockPixels(contentPixMap);
-
- // Draw the text into the offsceen world...
- // generate Pascal strings for drawing
- Str255 captionStringToDraw;
- strcpy((char *)captionStringToDraw, mCaption);
- c2pstr((char *)captionStringToDraw);
-
- // Set colors
- ::RGBBackColor(&mBackColor);
- ::RGBForeColor(&mForeColor);
-
- ::MoveTo(0, mFontInfo.ascent);
- ::DrawString(captionStringToDraw);
-
- // After drawing the string, unlock the offscreen buffer in memory
- // and set the port and device back to the original
- ::UnlockPixels(contentPixMap);
- ::SetGWorld(currentPort, currentDevice);
- }// try
-
- // error handling
- catch (CLabelError &labelError)
- {
- labelError.HandleError();
- }
-
- return theErr; // pass back the error condition -- should only fail if low mem
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- //
- // CLabelControl::Rotate90
- //
- // inputGWorld a GWorld containing a bitmap to be rotated by 90 degrees CCW
- // rotate90GWorld a GWorld containing the results of the 90 degree rotation
- //
- // Provided an inputGworld this routine rotates it 90 degrees CCW. A pointer
- // to an output GWorld is provided as input. This GWorld is alloc'd by the
- // rotation routine and returned.
- //
-
- QDErr CLabelControl::Rotate90(const GWorldPtr inputGWorld, GWorldPtr &rotate90GWorld)
- {
- try
- {
- // create the output buffer (--> rotateGWorld):
- PixMapHandle inputPixMap = GetGWorldPixMap(inputGWorld); // get the PixMap from our unrotated GWorld
- ::LockPixels(inputPixMap);
- const Rect inputBounds = (**inputPixMap).bounds; // get the bounds of the unrotated GWorld
- // create bounds of rotated GWorld by swapping right and bottom coords for rect @ 0,0
- const Rect rotate90Bounds = { 0, 0, inputBounds.right, inputBounds.bottom };
- QDErr theErr = ::NewGWorld(&rotate90GWorld, twoHundredFiftySixColorsDepth , &rotate90Bounds, 0, nil, 0);
- ASSERT(theErr == noErr, "alloc rotate90GWorld failed!");
- if(theErr != noErr)
- throw CLabelError(GWORLD_ALLOCATION_ERROR, this);
-
- if (theErr != noErr) return theErr; // bail and return the err code
- PixMapHandle rotate90PixMap = GetGWorldPixMap(rotate90GWorld); // get the PixMap from our rotated GWorld
- ::LockPixels(rotate90PixMap);
- ::HLock((Handle)rotate90PixMap);
-
- // now get the rowbytes for each bitmap since we need these to compute our addresses
- short inputRowBytes = GetRowBytes(inputPixMap);
- short rotate90RowBytes = GetRowBytes(rotate90PixMap);
-
- // walk each pixel in the source PixMap and copy it to the rotated PixMap
- Ptr inputPixMapBaseAddr = GetPixBaseAddr(inputPixMap); // always get the addr via this function
- Ptr rotate90PixMapBaseAddr = GetPixBaseAddr(rotate90PixMap); // always get the addr via this function
-
- unsigned char * src; // pointer to the begin of a src row (in scanline order)
- unsigned char * dst; // pointer to the begin of a dst row (in scanline order)
- unsigned char * curColumn = nil;
-
- for (int row = 0; row < inputBounds.bottom; row++) // do all the rows
- {
- src = (unsigned char *)(inputPixMapBaseAddr + (inputRowBytes * row)); // init to begininning of current row
- curColumn = (unsigned char *)(rotate90PixMapBaseAddr + row);// init to point to first pixel of first row
-
- for (int column = 0; column < inputBounds.right; column++)// do all the columns
- {
- dst = curColumn + ((inputBounds.right - column - 1) * rotate90RowBytes);
- *dst = src[column];
- }// columns
- }// rows
-
- ::UnlockPixels(inputPixMap);
- }// try
-
- // error handling
- catch (CLabelError &labelError)
- {
- labelError.HandleError();
- }
-
- return noErr;
- }
-
- // end-of-file ////////////////////////////////////////////////////////////////
-
-